package mybatis.testDemo.datasource;

import com.mockrunner.mock.jdbc.*;
import mybatis.testDemo.MybatisBean;
import org.apache.ibatis.plugin.Interceptor;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.Assert;

import javax.sql.DataSource;

import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import java.sql.SQLException;
import java.sql.Types;
@Deprecated
@Configuration
public class EmbedDataSource {
    @Test
    public void test1(){
//        InternalMockHandler handler = new InternalMockHandler();
    }

    public static void setupSqlSessionFactoryForEMBED(AnnotationConfigApplicationContext applicationContext) throws SQLException {

        GenericBeanDefinition definition = new GenericBeanDefinition();
        definition.setBeanClass(SqlSessionFactoryBean.class);
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);

        definition.getPropertyValues().add("configuration", configuration);
        definition.getPropertyValues().add("dataSource", dataSource());
        Interceptor interceptor = MybatisBean.MapperConfiguration.AddOrgCodeForPageInteceptor();
        Interceptor pageInterceptor = MybatisBean.MapperConfiguration.PageInterceptor();
        Interceptor[] interceptors = {pageInterceptor,interceptor};
        org.springframework.core.io.ClassPathResource classPathResource = new org.springframework.core.io.ClassPathResource("sqlmap/MapperInterface.xml");
        definition.getPropertyValues().add("plugins", interceptors);
        definition.getPropertyValues().add("mapperLocations", classPathResource);
        applicationContext.registerBeanDefinition("sqlSessionFactory", definition);
    }

    @Bean
    public static DataSource dataSource() throws SQLException {

        MockConnection mockcon = mock(MockConnection.class);
        MockPreparedStatement mockPreparedStatementForPage = metaExtractForPage();
        MockPreparedStatement mockPreparedStatementForPage2 = metaExtractForPage();
        MockPreparedStatement mockPreparedStatement = metaExtractForList();
        MockPreparedStatement mockPreparedStatement2 = metaExtractForList();

        MockPreparedStatement mockPreparedStatementForVoid = metaExtractForVoid();
        MockPreparedStatement metaExtractForMap = metaExtractForMap();
        MockPreparedStatement metaExtractForCount = metaExtractForCount();
        MockPreparedStatement metaExtractForSequence = metaExtractForSequence();
        MockPreparedStatement metaExtractForCount2 = metaExtractForCount();
        /**
         *  protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
         *  connection.createStatement() => mockPrepareStatement.
         */
        given(mockcon.prepareStatement("INSERT INTO user_temp  ( id,\n" +
                "remark,\n" +
                "version )  VALUES  ( ?,\n" +
                "?,\n" +
                "? )"))
                .willReturn(mockPreparedStatement2);

        given(mockcon.prepareStatement("INSERT INTO user_temp  ( remark ) VALUES( ? )",1003,1007))
                .willReturn(mockPreparedStatement2);

        given(mockcon.prepareStatement("DELETE FROM user \n" +
                " \n" +
                " WHERE (name = ?)"))
                .willReturn(mockPreparedStatement2);
        given(mockcon.prepareStatement("SELECT  \n" +
                "id,name\n" +
                "  FROM user"))
                .willReturn(mockPreparedStatement2);
        given(mockcon.prepareStatement("SELECT id,name,phone,version FROM user WHERE id IN ( ? , ? , ? , ? , ? , ? )"))
                .willReturn(mockPreparedStatement2);
        given(mockcon.prepareStatement("select * from users where id=? and id1=? and orgCode=role2"))
                .willReturn(mockPreparedStatement2);
        given(mockcon.prepareStatement("SELECT  \n" +
                "name\n" +
                "  FROM user \n" +
                " \n" +
                " WHERE (phone = ?)"))
                .willReturn(mockPreparedStatement2);
        given(mockcon.prepareStatement("select nextval('user_account_sequence')"))
                .willReturn(metaExtractForSequence);
        given(mockcon.prepareStatement("SELECT COUNT(*)  FROM user_temp  WHERE       (  remark = ? )",1003,1007))
                .willReturn(metaExtractForCount);
        given(mockcon.prepareStatement("select count(0) from ( \n" +
                "SELECT  \n" +
                "id,name\n" +
                "  FROM user\n" +
                " ) tmp_count"))
                .willReturn(metaExtractForCount);

        given(mockcon.prepareStatement("select count(0) from ( \n" +
                "select * from users where orgCode=role1\n" +
                " ) tmp_count", 1003, 1007))
                .willReturn(metaExtractForCount);
        given(mockcon.prepareStatement("select count(0) from ( \n" +
                "select * from users where orgCode=role2\n" +
                " ) tmp_count", 1003, 1007))
                .willReturn(metaExtractForCount2);
        given(mockcon.prepareStatement("select count(0) from ( \n" +
                "select * from users where id=? and orgCode=role2\n" +
                " ) tmp_count", 1003, 1007))
                .willReturn(metaExtractForCount2);
        given(mockcon.prepareStatement("select count(0) from ( \n" +
                "select * from users where id=? and id1=? and orgCode=role2\n" +
                " ) tmp_count", 1003, 1007))
                .willReturn(metaExtractForCount2);
        given(mockcon.prepareStatement("select count(0) from ( \n" +
                "select * from users where id=? and id1=? and orgCode=role2\n" +
                " ) tmp_count"))
                .willReturn(metaExtractForCount2);
        given(mockcon.prepareStatement("select count(0) from ( \n" +
                "select * from users where           \n" +
                "            id=? and id1=? and orgCode=role2\n" +
                " ) tmp_count", 1003, 1007))
                .willReturn(metaExtractForCount2);

        given(mockcon.prepareStatement("select key,val from users", 1003, 1007))
                .willReturn(metaExtractForMap);
        given(mockcon.prepareStatement("select * from users where  count=222", 1003, 1007))
                .willReturn(mockPreparedStatement);
        given(mockcon.prepareStatement("select * from users where  count=222", 1003, 1007))
                .willReturn(mockPreparedStatement);
        given(mockcon.prepareStatement("select * from users where  count=222 and orgCode=role1", 1003, 1007))
                .willReturn(mockPreparedStatement);
        given(mockcon.prepareStatement("select * from users where orgCode=role1", 1003, 1007))
                .willReturn(mockPreparedStatement);
        given(mockcon.prepareStatement("select * from users", 1003, 1007))
                .willReturn(mockPreparedStatement);
        given(mockcon.prepareStatement("select * from users where           \n" +
                "            id=? and id1=? and orgCode=role2", 1003, 1007))
                .willReturn(mockPreparedStatement);
        given(mockcon.prepareStatement("select * from users where id=? and id1=? and orgCode=role2", 1003, 1007))
                .willReturn(mockPreparedStatement);
        given(mockcon.prepareStatement("select * from users where id=? and id1=? and orgCode=role1", 1003, 1007))
                .willReturn(mockPreparedStatement);
        given(mockcon.prepareStatement("select key,val from users where orgCode=role1", 1003, 1007))
                .willReturn(mockPreparedStatement2);

        /**
         *  注意sql需要全部匹配
         */
        given(mockcon.prepareStatement("select * from users where orgCode=role1\n" +
                " LIMIT ? ", 1003, 1007))
                .willReturn(mockPreparedStatementForPage);
        given(mockcon.prepareStatement("select * from users where orgCode=role2\n" +
                " LIMIT ? ", 1003, 1007))
                .willReturn(mockPreparedStatementForPage2);
        given(mockcon.prepareStatement("select * from users where id=? and orgCode=role2\n" +
                " LIMIT ? ", 1003, 1007))
                .willReturn(mockPreparedStatementForPage2);
        given(mockcon.prepareStatement("select * from users where id=? and id1=? and orgCode=role2\n" +
                " LIMIT ? ", 1003, 1007))
                .willReturn(mockPreparedStatementForPage2);
        given(mockcon.prepareStatement("select * from users where           \n" +
                "            id=? and id1=? and orgCode=role2\n" +
                " LIMIT ? ", 1003, 1007))
                .willReturn(mockPreparedStatementForPage2);
        given(mockcon.prepareStatement("SELECT  \n" +
                "id,name\n" +
                "  FROM user\n" +
                " LIMIT ? "))
                .willReturn(mockPreparedStatementForPage2);

        given(mockcon.prepareStatement("select ${val}", 1003, 1007))
                .willReturn(mockPreparedStatementForVoid);
        given(mockcon.prepareStatement("select ?", 1003, 1007))
                .willReturn(mockPreparedStatementForVoid);
        given(mockcon.prepareStatement("select 2", 1003, 1007))
                .willReturn(mockPreparedStatementForVoid);
        given(mockcon.prepareStatement("select 3", 1003, 1007))
                .willReturn(mockPreparedStatementForVoid);
        given(mockcon.prepareStatement("INSERT INTO user_account  ( id,\n" +
                "money,\n" +
                "version )  VALUES  ( ?,\n" +
                "?,\n" +
                "? )"))
                .willReturn(mockPreparedStatementForVoid);
        given(mockcon.prepareStatement("UPDATE user  SET name=?,\n" +
                "phone=?,\n" +
                "version=?,\n" +
                "\n" +
                "\n" +
                "name=?  \n" +
                " \n" +
                " WHERE (phone = ? AND version = ?)"))
                .willReturn(mockPreparedStatementForVoid);

        given(mockcon.prepareStatement("update user set name='hcj'", 1003, 1007)).willReturn(mockPreparedStatementForVoid);
        given(mockcon.prepareStatement("update user set name='hcj' where id=1", 1003, 1007)).willReturn(mockPreparedStatementForVoid);
        given(mockcon.prepareStatement("UPDATE user  SET name=?,\n" +
                "phone=?,\n" +
                "version=?  \n" +
                " \n" +
                " WHERE (name = ? AND version = ?)")).willReturn(mockPreparedStatementForVoid);
        given(mockcon.prepareStatement("UPDATE user  SET name=?,\n" +
                "phone=?,\n" +
                "version=?  \n" +
                " \n" +
                " WHERE (name = ? AND version = ?)")).willReturn(mockPreparedStatementForVoid);
        given(mockcon.prepareStatement("INSERT INTO user  ( id,\n" +
                "name,\n" +
                "phone,\n" +
                "version )  VALUES  ( ?,\n" +
                "?,\n" +
                "?,\n" +
                "? )"))
                .willReturn(mockPreparedStatementForVoid);
        given(mockcon.prepareStatement("insert into users(username) \n" +
                "         values(  \n" +
                "            ?\n" +
                "         , \n" +
                "            ?\n" +
                "         , \n" +
                "            ?\n" +
                "         , \n" +
                "            ?\n" +
                "         )", 1003, 1007))
                .willReturn(mockPreparedStatementForVoid);

        given(mockcon.prepareStatement("insert into users(username) \n" +
                "         values(  \n" +
                "            ?\n" +
                "         , \n" +
                "            ?\n" +
                "         , \n" +
                "            ?\n" +
                "         )", 1003, 1007))
                .willReturn(mockPreparedStatementForVoid);

        given(mockPreparedStatement.getUpdateCount()).willReturn(-1);
        given(mockPreparedStatement2.getUpdateCount()).willReturn(-1);
        given(mockPreparedStatementForVoid.getUpdateCount()).willReturn(-1);
        given(metaExtractForMap.getUpdateCount()).willReturn(-1);
        given(mockPreparedStatementForPage.getUpdateCount()).willReturn(-1);

        MockDataSource mockDataSource = mock(MockDataSource.class);
        given(mockDataSource.getConnection()).willReturn(mockcon);
        MockDatabaseMetaData mockDatabaseMetaData = new MockDatabaseMetaData();
        mockDatabaseMetaData.setURL("jdbc:mysql://localhost:3306/test");

        given(mockDataSource.getConnection().getMetaData()).willReturn(mockDatabaseMetaData);
        Assert.notNull(mockDataSource.getConnection());

        return mockDataSource;
    }
    public static MockPreparedStatement metaExtractForVoid() throws SQLException {
        MockPreparedStatement mockPreparedStatement = mock(MockPreparedStatement.class);
        given(mockPreparedStatement.getResultSet()).willReturn(null);
        return mockPreparedStatement;
    }

    public static MockPreparedStatement metaExtractForMap() throws SQLException {

        MockPreparedStatement mockPreparedStatement = mock(MockPreparedStatement.class);
        MockResultSet resultSetMock = mock(MockResultSet.class);
        MockResultSetMetaData mockResultSetMetaData = new MockResultSetMetaData();
        mockResultSetMetaData.setColumnCount(2);

        mockResultSetMetaData.setColumnLabel(1, "key");
        mockResultSetMetaData.setColumnLabel(2, "val");

        mockResultSetMetaData.setColumnName(1, "key");
        mockResultSetMetaData.setColumnName(2, "val");
        mockResultSetMetaData.setColumnType(1, Types.VARCHAR);
        mockResultSetMetaData.setColumnType(2, Types.VARCHAR);

        mockResultSetMetaData.setColumnClassName(1, String.class.getName());
        mockResultSetMetaData.setColumnClassName(2, String.class.getName());
        given(resultSetMock.getMetaData()).willReturn(mockResultSetMetaData);

        given(resultSetMock.getString("key")).willReturn("name", "name1", "name2", "name3");
        given(resultSetMock.getString("val")).willReturn("hcj", "hcj1", "hcj2", "hcj3");

        given(resultSetMock.next()).willReturn(true, true, true, true, false);
        given(mockPreparedStatement.getResultSet()).willReturn(resultSetMock);
        return mockPreparedStatement;
    }

    public static MockPreparedStatement metaExtractForList() throws SQLException {
        MockPreparedStatement mockPreparedStatement = mock(MockPreparedStatement.class);
        MockResultSet resultSetMock = mock(MockResultSet.class);

        MockResultSetMetaData mockResultSetMetaData = new MockResultSetMetaData();
        mockResultSetMetaData.setColumnCount(1);
        mockResultSetMetaData.setColumnLabel(1, "list");
        mockResultSetMetaData.setColumnName(1, "list");
        mockResultSetMetaData.setColumnType(1, Types.VARCHAR);
        mockResultSetMetaData.setColumnClassName(1, String.class.getName());
        given(resultSetMock.getMetaData()).willReturn(mockResultSetMetaData);
        given(resultSetMock.getString("list")).willReturn("hello world", "tomorrow", "firm");
        given(resultSetMock.next()).willReturn(true, false);
        given(mockPreparedStatement.getResultSet()).willReturn(resultSetMock);
        return mockPreparedStatement;
    }

    public static MockPreparedStatement metaExtractForPage() throws SQLException {
        MockPreparedStatement mockPreparedStatement = mock(MockPreparedStatement.class);
        MockResultSet resultSetMock = mock(MockResultSet.class);
        MockResultSetMetaData mockResultSetMetaData = new MockResultSetMetaData();
        mockResultSetMetaData.setColumnCount(1);
        mockResultSetMetaData.setColumnLabel(1, "list");
        mockResultSetMetaData.setColumnName(1, "list");
        mockResultSetMetaData.setColumnType(1, Types.VARCHAR);
        mockResultSetMetaData.setColumnClassName(1, String.class.getName());
        given(resultSetMock.getMetaData()).willReturn(mockResultSetMetaData);
        given(resultSetMock.getString("list")).willReturn("hello world", "tomorrow", "firm");
        given(resultSetMock.next()).willReturn(true, false);
        given(mockPreparedStatement.getResultSet()).willReturn(resultSetMock);
        return mockPreparedStatement;
    }

    public static MockPreparedStatement metaExtractForSequence() throws SQLException {
        MockPreparedStatement mockPreparedStatement = mock(MockPreparedStatement.class);
        MockResultSet resultSetMock = mock(MockResultSet.class);

        MockResultSetMetaData mockResultSetMetaData = new MockResultSetMetaData();
        mockResultSetMetaData.setColumnCount(1);
        mockResultSetMetaData.setColumnLabel(1, "nextval");
        mockResultSetMetaData.setColumnName(1, "nextval");
        mockResultSetMetaData.setColumnType(1, Types.VARCHAR);
        mockResultSetMetaData.setColumnClassName(1, String.class.getName());
        given(resultSetMock.getMetaData()).willReturn(mockResultSetMetaData);
        given(resultSetMock.getString("nextval")).willReturn("10");
        given(resultSetMock.next()).willReturn(true, false);
        given(mockPreparedStatement.getResultSet()).willReturn(resultSetMock);
        return mockPreparedStatement;
    }

    public static MockPreparedStatement metaExtractForCount() throws SQLException {
        MockPreparedStatement mockPreparedStatement = mock(MockPreparedStatement.class);
        MockResultSet resultSetMock = mock(MockResultSet.class);

        MockResultSetMetaData mockResultSetMetaData = new MockResultSetMetaData();
        mockResultSetMetaData.setColumnCount(1);
        mockResultSetMetaData.setColumnLabel(1, "tmp_count");
        mockResultSetMetaData.setColumnName(1, "tmp_count");
        mockResultSetMetaData.setColumnType(1, Types.BIGINT);
        mockResultSetMetaData.setColumnClassName(1, Long.class.getName());
        given(resultSetMock.getMetaData()).willReturn(mockResultSetMetaData);
        given(resultSetMock.getLong("tmp_count")).willReturn(10L);
        given(resultSetMock.next()).willReturn(true, false);
        given(mockPreparedStatement.getResultSet()).willReturn(resultSetMock);
        return mockPreparedStatement;
    }



}
